package com.xiaotao.http.core.response;

import com.xiaotao.http.core.annotation.WebController;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.HashMap;

public class HttpResponse {
    public int code;
    public String msg;
    protected HashMap<String,String> headers = new HashMap<>();
    protected Socket socket;
    protected boolean hasHeaderSend = false;
    public HttpResponse(Socket socket) {
        this.socket = socket;
        // 设定一些默认的Header
        setStatus(200, "OK");
        setHeader("Connection", "close");
        setHeader("Content-Type", "text/html;charset=utf-8");
        setHeader("Server", "xiaotao HTTP Server");
    }
    /**
     * 设置HTTP响应报文的响应标头（header）
     * @param key
     * @param value
     * @return
     */
    public HttpResponse setHeader(String key, String value){
        this.headers.put(key, value);

        //  return this用于实现链式调用（也叫流式调用）
        return this;
    }
    /**
     * 设置HTTP响应报文初始行的数据
     * @param code  响应码
     * @param msg   响应消息
     * @return
     */
    public HttpResponse setStatus(int code, String msg) {
        this.code = code;
        this.msg = msg;
        return this;
    }

    public HttpResponse setContentLength(int length) {
        setHeader("Content-Length", "" + length);
        return this;
    }

    public HttpResponse setContentType(String type) {
        setHeader("Content-Type", type);
        return this;
    }

    /**
     * 获取HTTP报文Header内容字符串（带空行）
     * @return
     */
    public String getHeaderContext() {
        StringBuilder sb = new StringBuilder();
        sb.append("HTTP/1.1 ").append(this.code).append(" ").append(this.msg).append("\r\n");
        for (String key: headers.keySet()) {
            sb.append(key).append(": ").append(headers.get(key)).append("\r\n");
        }
        sb.append("\r\n");
        return sb.toString();
    }

    /**
     * 向HTTP报文响应体发送字符串
     * @param str
     * @return
     * @throws IOException
     */
    public HttpResponse write(String str) throws IOException {
        write(str.getBytes());
        return this;
    }

    /**
     * 向HTTP报文响应体发送二进制字节数据
     * @param data
     * @return
     * @throws IOException
     */
    public HttpResponse write(byte[] data) throws IOException {
        write(data,0 , data.length);
        return this;
    }

    /**
     * 向HTTP报文响应体发送二进制字节数据
     * @param data 数据
     * @param off 从data数组的第off位开始
     * @param len 长度
     * @return
     * @throws IOException
     */
    public HttpResponse write(byte[] data, int off, int len) throws IOException {
        // 如果没发送过header 则先发送header
        if (hasHeaderSend == false) {
            socket.getOutputStream().write(getHeaderContext().getBytes());
            hasHeaderSend = true;
        }
        socket.getOutputStream().write(data, off, len);
        return this;
    }
    public void sendFile(File file) throws IOException {
        String suffix;
        String name = file.getName();
        suffix = name.substring(name.lastIndexOf('.')+1);
        sendFile(file, MimeTypeMap.getContentType(suffix));
    }
    /**
     * 直接响应一个文件（仅设置Header的Content-Length和Content-Type，其他属性需提前自行设置）
     * @param file 文件路径
     * @throws IOException
     */
    public void sendFile(File file, String contentType) throws IOException {
        if (!file.exists()) {
            /**
             * 将404重定向到文件
             * 将就着用，尚未实现响应重定向和错误类
             */
            File page404 = new File("static/404.html");
            if (page404.exists() && page404.isFile()) {
                sendFile(page404, "text/html");
                return;
            }
            // 文件不存在直接404
            String body = "<center><h1>404 Not Found</h1>" +
                            "<hr>" +
                            "Power by: Xiaotao HTTP Server" +
                            "</center>";
            setStatus(404, "NOT FOUND");
            setHeader("Content-Length", "" + body.length());
            write(body);
            return;
        }
        // 设定文件长度
        setHeader("Content-Length", "" + file.length());
        setContentType(contentType);
        // 读取文件内容并写到socket
        FileInputStream inputStream = new FileInputStream(file);
        byte[] bytes = new byte[8192];
        int cnt = 0;
        while( (cnt = inputStream.read(bytes)) != -1) {
            write(bytes, 0, cnt);
        }
        inputStream.close();
    }
}
